﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Media;
using System.Windows.Threading;
using Telerik.Windows.Controls;

namespace ServerCrafter.ClassLibrary
{
    public static class ServerOutputHandler
    {
        private static RadRichTextBox textBox;

        public static bool IsAutoScrollChecked = true;

        /// <summary>
        /// Initalizes the ServerOutputHandler by invoking the specified text box.
        /// </summary>
        /// <param name="textBoxRef">The RadRichTextBox to which the server output will be outputed to.</param>
        public static void Initialize(this RadRichTextBox textBoxRef)
        {
            Logger.WriteInfo("Initializing server output handler.");
            textBox = textBoxRef;

            try
            {
                Logger.WriteInfo("Invoking text box.");

                Logger.WriteInfo("Text box has been invoked.");
            }
            catch (InvalidEnumArgumentException exception)
            {
                Logger.WriteSevere("Could not invoke text box. Priority is not a valid priority.");
                Logger.WriteSevere("\tException: " + exception);
            }
            catch (ArgumentNullException exception)
            {
                Logger.WriteSevere("Could not invoke text box. Method is null.");
                Logger.WriteSevere("\tException: " + exception);
            }
            catch (ArgumentException exception)
            {
                Logger.WriteSevere("Could not invoke text box. Priority is equal to Inactive.");
                Logger.WriteSevere("\tException: " + exception);
            }

            Logger.WriteInfo("Server output handler initialization has completed.");
        }

        /// <summary>
        /// Catches the server output and passes it on for parsing and outputing.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="eventArgs">The <see cref="DataReceivedEventArgs"/> instance containing the event data.</param>
        public static void ServerOutputReceived(object sender, DataReceivedEventArgs eventArgs)
        {
            Logger.WriteInfo("Server output data received: " + eventArgs.Data + ".");
            ParseServerOutput(eventArgs.Data);
        }

        /// <summary>
        /// Parses the server output and passes it on for outputing.
        /// </summary>
        /// <param name="msg">The MSG.</param>
        private static void ParseServerOutput(string msg)
        {
            Logger.WriteInfo("Starting to parse server output data.");

            if (msg == "") return;
            msg += "\n";

            MsgType msgType;
            if (msg.Contains(" logged in with entity id "))
                msgType = MsgType.PlayerJoin;
            else if (msg.Contains(" lost connection: "))
                msgType = MsgType.PlayerLeave;
            else if (msg.Contains("[INFO]") && !msg.Contains("[STDERR]"))
                msgType = MsgType.Info;
            else if (msg.Contains("[WARNING]"))
                msgType = MsgType.Warning;
            else if (msg.Contains("[SEVERE]") || msg.Contains("[STDERR]"))
                msgType = MsgType.Severe;
            else
                msgType = MsgType.Unknown;

            OutputToTextBox(msg, msgType);
        }

        /// <summary>
        /// Outputs to text box.
        /// </summary>
        /// <param name="msg">The MSG.</param>
        /// <param name="msgType">Type of the MSG.</param>
        private static void OutputToTextBox(string msg, MsgType msgType)
        {
            switch (msgType)
            {
                case MsgType.Info:
                    Logger.WriteInfo("Messege is of type 'Info'. Outputing to text box.");
                    textBox.Insert(msg, Settings.ServerOutputColors.Info);
                    break;

                case MsgType.Warning:
                    Logger.WriteInfo("Messege is of type 'Warning'. Outputing to text box.");
                    textBox.Insert(msg, Settings.ServerOutputColors.Warning);
                    break;

                case MsgType.Severe:
                    Logger.WriteInfo("Messege is of type 'Severe'. Outputing to text box.");
                    textBox.Insert(msg, Settings.ServerOutputColors.Severe);
                    break;

                case MsgType.PlayerJoin:
                    Logger.WriteInfo("Messege is of type 'Player Join'. Outputing to text box.");
                    textBox.Insert(msg, Settings.ServerOutputColors.PlayerJoin);
                    PlayerEvents.Join(msg);
                    break;

                case MsgType.PlayerLeave:
                    Logger.WriteInfo("Messege is of type 'Player Leave'. Outputing to text box.");
                    textBox.Insert(msg, Settings.ServerOutputColors.PlayerLeave);
                    PlayerEvents.Leave(msg);
                    break;

                case MsgType.Unknown: Logger.WriteInfo("Messege is of unknown type. Outputing to text box.");
                    textBox.Insert(msg, Settings.ServerOutputColors.Unknown);
                    break;
            }

            ScrollToBottom();
        }

        /// <summary>
        /// Scrolls to bottom of the textbox.
        /// </summary>
        private static void ScrollToBottom()
        {
            if (!IsAutoScrollChecked) return;

            textBox.Dispatcher.Invoke((Action) (() => textBox.ScrollToVerticalOffset(double.MaxValue)));
        }

        /// <summary>
        /// Enumuration containing all message types.
        /// </summary>
        private enum MsgType
        {
            Info,
            Warning,
            Severe,
            PlayerJoin,
            PlayerLeave,
            Unknown,
        }
    }

    internal static class RadRichTextBoxExtensions
    {
        public static void Insert(this RadRichTextBox textBox, string text, Color color)
        {

            textBox.Dispatcher.Invoke((Action) (() =>
                {
                    textBox.ChangeParagraphSpacingAfter(1.15);
                    textBox.ChangeFontSize(13.0);

                    textBox.ChangeTextForeColor(color);
                    textBox.Insert(text);
                }));
        }
    };
}